/* $RCSFile: CountryInfo.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.Core/Country/CountryInfo.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:28  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Xml;

namespace AddonNice.Country
{
	internal class CountryInfoEnglishNameComparer : IComparer
	{
		/// <summary>
		/// IComparable.Compare EnglishName implementation.
		/// </summary>
		public Int32 Compare(object obj1, object obj2) 
		{
			if(obj1 is CountryInfo && obj2 is CountryInfo) 
			{
				CountryInfo cInfo1 = (CountryInfo) obj1;
				CountryInfo cInfo2 = (CountryInfo) obj2;
				return new CaseInsensitiveComparer().Compare(cInfo1.EnglishName, cInfo2.EnglishName);
			}
			throw new ArgumentException("[E]CountryInfoEnglishNameComparer Compare object is not a CountryInfo");    
		}
	}

	internal class CountryInfoNameComparer : IComparer
	{
		/// <summary>
		/// IComparable.Compare Name implementation.
		/// </summary>
		public Int32 Compare(object obj1, object obj2) 
		{
			if(obj1 is CountryInfo && obj2 is CountryInfo) 
			{
				CountryInfo cInfo1 = (CountryInfo) obj1;
				CountryInfo cInfo2 = (CountryInfo) obj2;
				return new CaseInsensitiveComparer(System.Globalization.CultureInfo.CurrentUICulture).Compare(cInfo1.Name, cInfo2.Name);

			}
			throw new ArgumentException("[E]CountryInfoNameComparer Compare object is not a CountryInfo");    
		}
	}

	internal class CountryInfoDisplayNameComparer : IComparer
	{
		/// <summary>
		/// IComparable.Compare DisplayName implementation.
		/// </summary>
		public Int32 Compare(object obj1, object obj2) 
		{
			if(obj1 is CountryInfo && obj2 is CountryInfo) 
			{
				CountryInfo cInfo1 = (CountryInfo) obj1;
				CountryInfo cInfo2 = (CountryInfo) obj2;
				return new CaseInsensitiveComparer().Compare(cInfo1.DisplayName, cInfo2.DisplayName);
			}
			throw new ArgumentException("object is not a CountryInfo");    
		}
	}

	/// <summary>
	/// Represents information about a specific country 
	/// including name and translation in various languages.
	/// </summary>
	[Serializable]
	public class CountryInfo
	{
		string m_name;
		CountryInfo m_parent;
		CountryInfo[] m_childs;
        string m_displayName;
        string m_englishName;
		string m_threeLetterISOCountryName;
		string m_twoLetterISOCountryName;
		Int32 m_countryCode;
		bool m_inhabited;

		public CountryInfo()
		{
			m_countryCode				=	0;
			m_name						=	string.Empty;
            m_displayName               =	string.Empty;
			m_twoLetterISOCountryName	=	string.Empty;
			m_threeLetterISOCountryName =	string.Empty;
			m_englishName				=	"World";
			m_parent					=	null;
			m_childs					=	null;
			m_inhabited					=	true;
		}

		public CountryInfo(string name)
		{
			if ( string.IsNullOrEmpty(name) )
				throw new ArgumentNullException("name", "Country cannot be null");
			CountryInfo c = CountryTable.GetCountryInfoFromName(name);
			if (c == null)
				throw new ArgumentOutOfRangeException("name", name, "Invalid country");

			m_countryCode               =   c.CountryCode;
			m_name                      =   c.Name;
			m_twoLetterISOCountryName   =   c.TwoLetterISOCountryName;
			m_threeLetterISOCountryName =   c.ThreeLetterISOCountryName;
			m_englishName               =   c.EnglishName;
			m_parent                    =   c.GetParentCountryInfo();
			m_childs                    =   c.Childs;
			m_inhabited                 =   c.Inhabited;
		}

		/// <summary>
		/// Used internally to instantiate CountryInfo object
		/// </summary>
		internal CountryInfo(string name, CountryInfo parent, string englishName, bool inhabited, string twoLetterISOCountryName, string threeLetterISOCountryName, int countryCode)
		{
			m_name                      =   name;
			m_parent                    =   parent;
			m_englishName               =   englishName;
			m_inhabited                 =   inhabited;
			m_twoLetterISOCountryName   =   twoLetterISOCountryName;
			m_threeLetterISOCountryName =   threeLetterISOCountryName;
			m_countryCode               =   countryCode;
		}

		/// <summary>
		/// Returns a list of descendants of this country
		/// </summary>
		public CountryInfo[] Childs
		{
			get {return m_childs;}
			set {m_childs = value;}
		}

		/// <summary>
		/// Changes the parent CountryInfo of this object
		/// </summary>
		internal void SetParentCountryInfo(CountryInfo parent)
		{
			m_parent    =   parent;
		}

		/// <summary>
		/// Get a CountryInfo to the parent of this object
		/// </summary>
		public CountryInfo GetParentCountryInfo()
		{
			return m_parent;
		}

        /// <summary>
        /// Get a CountryInfo to the parent of this object
        /// </summary>
        public CountryInfo GetChildCountryInfo(string childName)
        {
            return CountryTable.RecurseGetCountryInfoFromName(childName, Childs);
        }
        
        /// <summary>
		/// Gets the list of supported cultures filtered by the specified CountryTypes.
		/// </summary>
		public static CountryInfo[] GetCountries(CountryTypes types)
		{
			return CountryTable.GetCountries(types, CountryFields.DisplayName);
		}

		/// <summary>
		/// Gets the list of supported cultures filtered by the specified CountryTypes.
		/// </summary>
		public static CountryInfo[] GetCountries(CountryTypes types, CountryFields sortBY)
		{
			return CountryTable.GetCountries(types, sortBY);
		}

		/// <summary>
		/// Gets the list of supported cultures filtered by the specified filter.
		/// </summary>
		public static CountryInfo[] GetCountries(string filter)
		{
			return CountryTable.GetCountriesFiltered(filter, CountryFields.None);
		}

		/// <summary>
		/// Gets the list of supported cultures filtered by the specified filter.
		/// </summary>
		public static CountryInfo[] GetCountries(string filter, CountryFields sortBY)
		{
			return CountryTable.GetCountriesFiltered(filter, sortBY);
		}

		public static SortedList<string,CountryInfo> GetDicCountries(string filter, CountryFields sortBY)
		{
			return CountryTable.GetDicCountriesFiltered(filter, sortBY);
		}

        /// <summary>
		/// Gets the country name in English.
		/// </summary>
		public string EnglishName
		{
			get{return m_englishName;}
			set{m_englishName = value;}
		}

		/// <summary>
		/// Gets the ISO 3166-2 three-letter code for the country of the current CountryInfo.
		/// </summary>
		public string ThreeLetterISOCountryName
		{
			get{return m_threeLetterISOCountryName;}
			set{m_threeLetterISOCountryName = value;}
		}

		/// <summary>
		/// Gets the ISO 3166-1 two-letter code for the country of the current CountryInfo.
		/// </summary>
		public string TwoLetterISOCountryName
		{
			get{return m_twoLetterISOCountryName;}
			set{m_twoLetterISOCountryName = value;}
		}

		/// <summary>
		/// Gets the ISO 3166 code for the country of the current CountryInfo.
		/// </summary>
		public Int32 CountryCode
		{
			get{return m_countryCode;}
			set{m_countryCode = value;}
		}

		/// <summary>
		/// Returns true if country is inhabited.
		/// </summary>
		public bool Inhabited
		{
			get{return m_inhabited;}
			set{m_inhabited = value;}
		}

		/// <summary>
		/// Gets the name in the current language if available or gets the default one.
		/// Is exposed as property so it can be easily binded
		/// </summary>
		public string DisplayName
		{
			get
			{
                if (string.IsNullOrEmpty(m_displayName))
                {
                    m_displayName           =   new CountryStoreResources().GetValue("COUNTRY_" + this.Name);
                    if (string.IsNullOrEmpty(m_displayName))
                        m_displayName       =   m_englishName;
                }
				return m_displayName;
			}
		}

		/// <summary>
		/// Gets the full country code name (Country-Region-Subregion)
		/// </summary>
		public string Name
		{
			get{return m_name;}
			set{m_name = value;}
		}
	
		/// <summary>
		/// Gets the name in the specified language if available or gets the default one.
		/// </summary>
		public string GetDisplayName(System.Globalization.CultureInfo c)
		{
			return new CountryStoreResources().GetValue(m_twoLetterISOCountryName, c);
		}

		/// <summary>
		/// Returns CultureInfo name
		/// </summary>
		public override string ToString()
		{
			return m_name;
		}
		
		/// <summary>
		/// Get a CountryInfo objects that represents 
		/// the country of the current thread
		/// </summary>
		public static CountryInfo CurrentCountry
		{
			get
			{
				try
				{
					// CS 13/11/04 this is not the current thread country but the executing computer env
					//return new CountryInfo(RegionInfo.CurrentRegion.Name);
					RegionInfo ri	=	new RegionInfo(System.Threading.Thread.CurrentThread.CurrentCulture.LCID);
					if ( ri == null )
						ri	=	RegionInfo.CurrentRegion;
					return new CountryInfo(ri.ThreeLetterISORegionName);
				}
				catch(ArgumentException)
				{
					return null;
				}
			}
		}
	}
}
